package watch

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"time"
)

var hashmark string        // 注释符
var listenedSection string // 被监听section，用于特定 section 的监听

// Config 结构体，定义了文件路径和map存储数据
type Config struct {
	Filepath string
	Conflist []map[string]map[string]string
}

// Listener接口，监听函数 ListenFunc 需实现该接口
type Listener interface {
	Listen(inifile string)
}

// 监听函数类型 ListenFunc
type ListenFunc func(inifile string) (*Config, error)

func init() {
	sysType := runtime.GOOS
	if sysType == "linux" {
		// LINUX系统
		hashmark = "#"
	}
	if sysType == "windows" {
		// windows系统
		hashmark = ";"
	}
}

// ListenFunc 的 Listener 接口实现
func (f ListenFunc) Listen(inifile string) (*Config, error) {
	return f(inifile)
}

//Filelisten 监听文件更改
func Filelisten(inifile string) (*Config, error) {
	conf := InitConfig(inifile)
	out, err := conf.ReadList()
	if err != nil {
		return nil, err
	}
	var equal bool = false
	for {
		reconf := InitConfig(inifile)
		reout, err := reconf.ReadList()
		if err != nil {
			return nil, err
		}
		if len(out) != len(reout) {
			c := InitConfig(inifile)
			c.Conflist = reout
			return c, nil
		}
		for _, sectionMap := range reout {
			for sectionName, keyMap := range sectionMap {
				for keyName, keyValue := range keyMap {
					equal = false
					for _, oldSectionMap := range out {
						oldKeyMap := oldSectionMap[sectionName]
						oldKeyValue := oldKeyMap[keyName]
						if oldKeyValue == keyValue {
							equal = true
						}
					}
					if equal == false {
						c := InitConfig(inifile)
						c.Conflist = reout
						fmt.Println(c)
						fmt.Println("run")
						return c, nil
					}
				}
			}
		}
		time.Sleep(1000)
	}
}

//Optionlisten 监听配置项更改
func Optionlisten(inifile string) (*Config, error) {
	conf := InitConfig(inifile)
	out, err := conf.ReadList()
	if err != nil {
		return nil, err
	}
	var equal bool = false
	for {
		reconf := InitConfig(inifile)
		reout, err := reconf.ReadList()
		if err != nil {
			return nil, err
		}
		renum := 0
		oldnum := 0
		for _, sectionMap := range reout {
			for sectionName, _ := range sectionMap {
				if sectionName == listenedSection {
					renum++
				}
			}
		}
		for _, sectionMap := range out {
			for sectionName, _ := range sectionMap {
				if sectionName == listenedSection {
					oldnum++
				}
			}
		}
		if oldnum != renum {
			c := InitConfig(inifile)
			c.Conflist = reout
			return c, nil
		}
		for _, sectionMap := range reout {
			for sectionName, keyMap := range sectionMap {
				if sectionName == listenedSection {
					for keyName, keyValue := range keyMap {
						equal = false
						for _, oldSectionMap := range out {
							for oldSectionName, _ := range oldSectionMap {
								if oldSectionName == listenedSection {
									oldKeyMap := oldSectionMap[sectionName]
									oldKeyValue := oldKeyMap[keyName]
									if oldKeyValue == keyValue {
										equal = true
									}
								}
							}
						}
						if equal == false {
							c := InitConfig(inifile)
							c.Conflist = reout
							return c, nil
						}
					}
				}
			}
		}
		time.Sleep(1000)
	}
}


//Watch 监听配置文件整个文件是否改变
func Watch(filename string, Listener ListenFunc) (*Config, error) {
	Listener = Filelisten
	return Listener.Listen(filename)
}


//WatchWithOption 监听配置文件某个选项的改变
func WatchWithOption(filename string, Listener ListenFunc, section string) (*Config, error) {
	listenedSection = section
	Listener = Optionlisten
	return Listener.Listen(filename)
}


//InitConfig 初始化结构体
func InitConfig(filepath string) *Config {
	c := new(Config)
	c.Filepath = filepath
	return c
}


//ReadList 读取所有文件配置属性
func (c *Config) ReadList() ([]map[string]map[string]string, error) {

	file, err := os.Open(c.Filepath)
	if err != nil {
		return nil, fmt.Errorf("Error in ReadList func, can't open the file ") // self define error
	}
	defer file.Close()
	var data map[string]map[string]string
	var sectionName string
	buf := bufio.NewReader(file)
	for {
		l, err := buf.ReadString('\n')
		line := strings.TrimSpace(l)
		if err != nil {
			if err != io.EOF {
				return nil, fmt.Errorf("Error in ReadList func, can't Read the file data ") // self define error
			}
			if len(line) == 0 {
				break
			}
		}
		switch {
		case len(line) == 0: //empty line
		case string(line[0]) == hashmark: // note line
		case line[0] == '[' && line[len(line)-1] == ']':
			sectionName = strings.TrimSpace(line[1 : len(line)-1])
			data = make(map[string]map[string]string)
			data[sectionName] = make(map[string]string)
		default:
			i := strings.IndexAny(line, "=")
			if i == -1 {
				fmt.Println("i = -1")
				continue
			}
			if sectionName == "" {
				sectionName = "defaultsection"
			}

			data = make(map[string]map[string]string)
			data[sectionName] = make(map[string]string)
			keyName := strings.TrimSpace(line[0:i])
			keyValue := strings.TrimSpace(line[i+1 : len(line)])
			data[sectionName][keyName] = keyValue
			if c.unique(sectionName, keyName) == true {
				c.Conflist = append(c.Conflist, data)
			}
		}

	}

	return c.Conflist, nil
}


// 判断一个 “section-key” 项是否可添加（未存在）
func (c *Config) unique(section string, key string) bool {
	for _, sectionMap := range c.Conflist {
		for sectionName, keyMap := range sectionMap {
			if sectionName == section {
				for keyName, _ := range keyMap {
					if keyName == key {
						return false
					}
				}

			}
		}
	}
	return true
}

// func main() {
// 	var listen ListenFunc = Filelisten //or Optionlisten
// 	inifile := "config2.ini"
// 	a, err := Watch(inifile, listen)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	} else {
// 		fmt.Println(a)
// 	}
// }

// func main() {
// 	var listen ListenFunc = Optionlisten //or Optionlisten
// 	inifile := "config2.ini"
// 	a, err := WatchWithOption(inifile, listen, "server")
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	} else {
// 		fmt.Println(a)
// 	}
// }
